home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 10 / AACD 10.iso / AACD / Games / WarpQuake / Src / in_win.c < prev    next >
C/C++ Source or Header  |  2000-05-22  |  27KB  |  1,240 lines

  1. /*
  2. Copyright (C) 1996-1997 Id Software, Inc.
  3.  
  4. This program is free software; you can redistribute it and/or
  5. modify it under the terms of the GNU General Public License
  6. as published by the Free Software Foundation; either version 2
  7. of the License, or (at your option) any later version.
  8.  
  9. This program is distributed in the hope that it will be useful,
  10. but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  
  12.  
  13. See the GNU General Public License for more details.
  14.  
  15. You should have received a copy of the GNU General Public License
  16. along with this program; if not, write to the Free Software
  17. Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
  18.  
  19. */
  20. // in_win.c -- windows 95 mouse and joystick code
  21. // 02/21/97 JCB Added extended DirectInput code to support external controllers.
  22.  
  23. #include <dinput.h>
  24. #include "quakedef.h"
  25. #include "winquake.h"
  26. #include "dosisms.h"
  27.  
  28. #define DINPUT_BUFFERSIZE           16
  29. #define iDirectInputCreate(a,b,c,d)    pDirectInputCreate(a,b,c,d)
  30.  
  31. HRESULT (WINAPI *pDirectInputCreate)(HINSTANCE hinst, DWORD dwVersion,
  32.     LPDIRECTINPUT * lplpDirectInput, LPUNKNOWN punkOuter);
  33.  
  34. // mouse variables
  35. cvar_t    m_filter = {"m_filter","0"};
  36.  
  37. int            mouse_buttons;
  38. int            mouse_oldbuttonstate;
  39. POINT        current_pos;
  40. int            mouse_x, mouse_y, old_mouse_x, old_mouse_y, mx_accum, my_accum;
  41.  
  42. static qboolean    restore_spi;
  43. static int        originalmouseparms[3], newmouseparms[3] = {0, 0, 1};
  44.  
  45. unsigned int uiWheelMessage;
  46. qboolean    mouseactive;
  47. qboolean        mouseinitialized;
  48. static qboolean    mouseparmsvalid, mouseactivatetoggle;
  49. static qboolean    mouseshowtoggle = 1;
  50. static qboolean    dinput_acquired;
  51.  
  52. static unsigned int        mstate_di;
  53.  
  54. // joystick defines and variables
  55. // where should defines be moved?
  56. #define JOY_ABSOLUTE_AXIS    0x00000000        // control like a joystick
  57. #define JOY_RELATIVE_AXIS    0x00000010        // control like a mouse, spinner, trackball
  58. #define    JOY_MAX_AXES        6                // X, Y, Z, R, U, V
  59. #define JOY_AXIS_X            0
  60. #define JOY_AXIS_Y            1
  61. #define JOY_AXIS_Z            2
  62. #define JOY_AXIS_R            3
  63. #define JOY_AXIS_U            4
  64. #define JOY_AXIS_V            5
  65.  
  66. enum _ControlList
  67. {
  68.     AxisNada = 0, AxisForward, AxisLook, AxisSide, AxisTurn
  69. };
  70.  
  71. DWORD    dwAxisFlags[JOY_MAX_AXES] =
  72. {
  73.     JOY_RETURNX, JOY_RETURNY, JOY_RETURNZ, JOY_RETURNR, JOY_RETURNU, JOY_RETURNV
  74. };
  75.  
  76. DWORD    dwAxisMap[JOY_MAX_AXES];
  77. DWORD    dwControlMap[JOY_MAX_AXES];
  78. PDWORD    pdwRawValue[JOY_MAX_AXES];
  79.  
  80. // none of these cvars are saved over a session
  81. // this means that advanced controller configuration needs to be executed
  82. // each time.  this avoids any problems with getting back to a default usage
  83. // or when changing from one controller to another.  this way at least something
  84. // works.
  85. cvar_t    in_joystick = {"joystick","0", true};
  86. cvar_t    joy_name = {"joyname", "joystick"};
  87. cvar_t    joy_advanced = {"joyadvanced", "0"};
  88. cvar_t    joy_advaxisx = {"joyadvaxisx", "0"};
  89. cvar_t    joy_advaxisy = {"joyadvaxisy", "0"};
  90. cvar_t    joy_advaxisz = {"joyadvaxisz", "0"};
  91. cvar_t    joy_advaxisr = {"joyadvaxisr", "0"};
  92. cvar_t    joy_advaxisu = {"joyadvaxisu", "0"};
  93. cvar_t    joy_advaxisv = {"joyadvaxisv", "0"};
  94. cvar_t    joy_forwardthreshold = {"joyforwardthreshold", "0.15"};
  95. cvar_t    joy_sidethreshold = {"joysidethreshold", "0.15"};
  96. cvar_t    joy_pitchthreshold = {"joypitchthreshold", "0.15"};
  97. cvar_t    joy_yawthreshold = {"joyyawthreshold", "0.15"};
  98. cvar_t    joy_forwardsensitivity = {"joyforwardsensitivity", "-1.0"};
  99. cvar_t    joy_sidesensitivity = {"joysidesensitivity", "-1.0"};
  100. cvar_t    joy_pitchsensitivity = {"joypitchsensitivity", "1.0"};
  101. cvar_t    joy_yawsensitivity = {"joyyawsensitivity", "-1.0"};
  102. cvar_t    joy_wwhack1 = {"joywwhack1", "0.0"};
  103. cvar_t    joy_wwhack2 = {"joywwhack2", "0.0"};
  104.  
  105. qboolean    joy_avail, joy_advancedinit, joy_haspov;
  106. DWORD        joy_oldbuttonstate, joy_oldpovstate;
  107.  
  108. int            joy_id;
  109. DWORD        joy_flags;
  110. DWORD        joy_numbuttons;
  111.  
  112. static LPDIRECTINPUT        g_pdi;
  113. static LPDIRECTINPUTDEVICE    g_pMouse;
  114.  
  115. static JOYINFOEX    ji;
  116.  
  117. static HINSTANCE hInstDI;
  118.  
  119. static qboolean    dinput;
  120.  
  121. typedef struct MYDATA {
  122.     LONG  lX;                   // X axis goes here
  123.     LONG  lY;                   // Y axis goes here
  124.     LONG  lZ;                   // Z axis goes here
  125.     BYTE  bButtonA;             // One button goes here
  126.     BYTE  bButtonB;             // Another button goes here
  127.     BYTE  bButtonC;             // Another button goes here
  128.     BYTE  bButtonD;             // Another button goes here
  129. } MYDATA;
  130.  
  131. static DIOBJECTDATAFORMAT rgodf[] = {
  132.   { &GUID_XAxis,    FIELD_OFFSET(MYDATA, lX),       DIDFT_AXIS | DIDFT_ANYINSTANCE,   0,},
  133.   { &GUID_YAxis,    FIELD_OFFSET(MYDATA, lY),       DIDFT_AXIS | DIDFT_ANYINSTANCE,   0,},
  134.   { &GUID_ZAxis,    FIELD_OFFSET(MYDATA, lZ),       0x80000000 | DIDFT_AXIS | DIDFT_ANYINSTANCE,   0,},
  135.   { 0,              FIELD_OFFSET(MYDATA, bButtonA), DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0,},
  136.   { 0,              FIELD_OFFSET(MYDATA, bButtonB), DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0,},
  137.   { 0,              FIELD_OFFSET(MYDATA, bButtonC), 0x80000000 | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0,},
  138.   { 0,              FIELD_OFFSET(MYDATA, bButtonD), 0x80000000 | DIDFT_BUTTON | DIDFT_ANYINSTANCE, 0,},
  139. };
  140.  
  141. #define NUM_OBJECTS (sizeof(rgodf) / sizeof(rgodf[0]))
  142.  
  143. static DIDATAFORMAT    df = {
  144.     sizeof(DIDATAFORMAT),       // this structure
  145.     sizeof(DIOBJECTDATAFORMAT), // size of object data format
  146.     DIDF_RELAXIS,               // absolute axis coordinates
  147.     sizeof(MYDATA),             // device data size
  148.     NUM_OBJECTS,                // number of objects
  149.     rgodf,                      // and here they are
  150. };
  151.  
  152. // forward-referenced functions
  153. void IN_StartupJoystick (void);
  154. void Joy_AdvancedUpdate_f (void);
  155. void IN_JoyMove (usercmd_t *cmd);
  156.  
  157.  
  158. /*
  159. ===========
  160. Force_CenterView_f
  161. ===========
  162. */
  163. void Force_CenterView_f (void)
  164. {
  165.     cl.viewangles[PITCH] = 0;
  166. }
  167.  
  168.  
  169. /*
  170. ===========
  171. IN_UpdateClipCursor
  172. ===========
  173. */
  174. void IN_UpdateClipCursor (void)
  175. {
  176.  
  177.     if (mouseinitialized && mouseactive && !dinput)
  178.     {
  179.         ClipCursor (&window_rect);
  180.     }
  181. }
  182.  
  183.  
  184. /*
  185. ===========
  186. IN_ShowMouse
  187. ===========
  188. */
  189. void IN_ShowMouse (void)
  190. {
  191.  
  192.     if (!mouseshowtoggle)
  193.     {
  194.         ShowCursor (TRUE);
  195.         mouseshowtoggle = 1;
  196.     }
  197. }
  198.  
  199.  
  200. /*
  201. ===========
  202. IN_HideMouse
  203. ===========
  204. */
  205. void IN_HideMouse (void)
  206. {
  207.  
  208.     if (mouseshowtoggle)
  209.     {
  210.         ShowCursor (FALSE);
  211.         mouseshowtoggle = 0;
  212.     }
  213. }
  214.  
  215.  
  216. /*
  217. ===========
  218. IN_ActivateMouse
  219. ===========
  220. */
  221. void IN_ActivateMouse (void)
  222. {
  223.  
  224.     mouseactivatetoggle = true;
  225.  
  226.     if (mouseinitialized)
  227.     {
  228.         if (dinput)
  229.         {
  230.             if (g_pMouse)
  231.             {
  232.                 if (!dinput_acquired)
  233.                 {
  234.                     IDirectInputDevice_Acquire(g_pMouse);
  235.                     dinput_acquired = true;
  236.                 }
  237.             }
  238.             else
  239.             {
  240.                 return;
  241.             }
  242.         }
  243.         else
  244.         {
  245.             if (mouseparmsvalid)
  246.                 restore_spi = SystemParametersInfo (SPI_SETMOUSE, 0, newmouseparms, 0);
  247.  
  248.             SetCursorPos (window_center_x, window_center_y);
  249.             SetCapture (mainwindow);
  250.             ClipCursor (&window_rect);
  251.         }
  252.  
  253.         mouseactive = true;
  254.     }
  255. }
  256.  
  257.  
  258. /*
  259. ===========
  260. IN_SetQuakeMouseState
  261. ===========
  262. */
  263. void IN_SetQuakeMouseState (void)
  264. {
  265.     if (mouseactivatetoggle)
  266.         IN_ActivateMouse ();
  267. }
  268.  
  269.  
  270. /*
  271. ===========
  272. IN_DeactivateMouse
  273. ===========
  274. */
  275. void IN_DeactivateMouse (void)
  276. {
  277.  
  278.     mouseactivatetoggle = false;
  279.  
  280.     if (mouseinitialized)
  281.     {
  282.         if (dinput)
  283.         {
  284.             if (g_pMouse)
  285.             {
  286.                 if (dinput_acquired)
  287.                 {
  288.                     IDirectInputDevice_Unacquire(g_pMouse);
  289.                     dinput_acquired = false;
  290.                 }
  291.             }
  292.         }
  293.         else
  294.         {
  295.             if (restore_spi)
  296.                 SystemParametersInfo (SPI_SETMOUSE, 0, originalmouseparms, 0);
  297.  
  298.             ClipCursor (NULL);
  299.             ReleaseCapture ();
  300.         }
  301.  
  302.         mouseactive = false;
  303.     }
  304. }
  305.  
  306.  
  307. /*
  308. ===========
  309. IN_RestoreOriginalMouseState
  310. ===========
  311. */
  312. void IN_RestoreOriginalMouseState (void)
  313. {
  314.     if (mouseactivatetoggle)
  315.     {
  316.         IN_DeactivateMouse ();
  317.         mouseactivatetoggle = true;
  318.     }
  319.  
  320. // try to redraw the cursor so it gets reinitialized, because sometimes it
  321. // has garbage after the mode switch
  322.     ShowCursor (TRUE);
  323.     ShowCursor (FALSE);
  324. }
  325.  
  326.  
  327. /*
  328. ===========
  329. IN_InitDInput
  330. ===========
  331. */
  332. qboolean IN_InitDInput (void)
  333. {
  334.     HRESULT        hr;
  335.     DIPROPDWORD    dipdw = {
  336.         {
  337.             sizeof(DIPROPDWORD),        // diph.dwSize
  338.             sizeof(DIPROPHEADER),       // diph.dwHeaderSize
  339.             0,                          // diph.dwObj
  340.             DIPH_DEVICE,                // diph.dwHow
  341.         },
  342.         DINPUT_BUFFERSIZE,              // dwData
  343.     };
  344.  
  345.     if (!hInstDI)
  346.     {
  347.         hInstDI = LoadLibrary("dinput.dll");
  348.         
  349.         if (hInstDI == NULL)
  350.         {
  351.             Con_SafePrintf ("Couldn't load dinput.dll\n");
  352.             return false;
  353.         }
  354.     }
  355.  
  356.     if (!pDirectInputCreate)
  357.     {
  358.         pDirectInputCreate = (void *)GetProcAddress(hInstDI,"DirectInputCreateA");
  359.  
  360.         if (!pDirectInputCreate)
  361.         {
  362.             Con_SafePrintf ("Couldn't get DI proc addr\n");
  363.             return false;
  364.         }
  365.     }
  366.  
  367. // register with DirectInput and get an IDirectInput to play with.
  368.     hr = iDirectInputCreate(global_hInstance, DIRECTINPUT_VERSION, &g_pdi, NULL);
  369.  
  370.     if (FAILED(hr))
  371.     {
  372.         return false;
  373.     }
  374.  
  375. // obtain an interface to the system mouse device.
  376.     hr = IDirectInput_CreateDevice(g_pdi, &GUID_SysMouse, &g_pMouse, NULL);
  377.  
  378.     if (FAILED(hr))
  379.     {
  380.         Con_SafePrintf ("Couldn't open DI mouse device\n");
  381.         return false;
  382.     }
  383.  
  384. // set the data format to "mouse format".
  385.     hr = IDirectInputDevice_SetDataFormat(g_pMouse, &df);
  386.  
  387.     if (FAILED(hr))
  388.     {
  389.         Con_SafePrintf ("Couldn't set DI mouse format\n");
  390.         return false;
  391.     }
  392.  
  393. // set the cooperativity level.
  394.     hr = IDirectInputDevice_SetCooperativeLevel(g_pMouse, mainwindow,
  395.             DISCL_EXCLUSIVE | DISCL_FOREGROUND);
  396.  
  397.     if (FAILED(hr))
  398.     {
  399.         Con_SafePrintf ("Couldn't set DI coop level\n");
  400.         return false;
  401.     }
  402.  
  403.  
  404. // set the buffer size to DINPUT_BUFFERSIZE elements.
  405. // the buffer size is a DWORD property associated with the device
  406.     hr = IDirectInputDevice_SetProperty(g_pMouse, DIPROP_BUFFERSIZE, &dipdw.diph);
  407.  
  408.     if (FAILED(hr))
  409.     {
  410.         Con_SafePrintf ("Couldn't set DI buffersize\n");
  411.         return false;
  412.     }
  413.  
  414.     return true;
  415. }
  416.  
  417.  
  418. /*
  419. ===========
  420. IN_StartupMouse
  421. ===========
  422. */
  423. void IN_StartupMouse (void)
  424. {
  425.     HDC            hdc;
  426.  
  427.     if ( COM_CheckParm ("-nomouse") ) 
  428.         return; 
  429.  
  430.     mouseinitialized = true;
  431.  
  432.     if (COM_CheckParm ("-dinput"))
  433.     {
  434.         dinput = IN_InitDInput ();
  435.  
  436.         if (dinput)
  437.         {
  438.             Con_SafePrintf ("DirectInput initialized\n");
  439.         }
  440.         else
  441.         {
  442.             Con_SafePrintf ("DirectInput not initialized\n");
  443.         }
  444.     }
  445.  
  446.     if (!dinput)
  447.     {
  448.         mouseparmsvalid = SystemParametersInfo (SPI_GETMOUSE, 0, originalmouseparms, 0);
  449.  
  450.         if (mouseparmsvalid)
  451.         {
  452.             if ( COM_CheckParm ("-noforcemspd") ) 
  453.                 newmouseparms[2] = originalmouseparms[2];
  454.  
  455.             if ( COM_CheckParm ("-noforcemaccel") ) 
  456.             {
  457.                 newmouseparms[0] = originalmouseparms[0];
  458.                 newmouseparms[1] = originalmouseparms[1];
  459.             }
  460.  
  461.             if ( COM_CheckParm ("-noforcemparms") ) 
  462.             {
  463.                 newmouseparms[0] = originalmouseparms[0];
  464.                 newmouseparms[1] = originalmouseparms[1];
  465.                 newmouseparms[2] = originalmouseparms[2];
  466.             }
  467.         }
  468.     }
  469.  
  470.     mouse_buttons = 3;
  471.  
  472. // if a fullscreen video mode was set before the mouse was initialized,
  473. // set the mouse state appropriately
  474.     if (mouseactivatetoggle)
  475.         IN_ActivateMouse ();
  476. }
  477.  
  478.  
  479. /*
  480. ===========
  481. IN_Init
  482. ===========
  483. */
  484. void IN_Init (void)
  485. {
  486.     // mouse variables
  487.     Cvar_RegisterVariable (&m_filter);
  488.  
  489.     // joystick variables
  490.     Cvar_RegisterVariable (&in_joystick);
  491.     Cvar_RegisterVariable (&joy_name);
  492.     Cvar_RegisterVariable (&joy_advanced);
  493.     Cvar_RegisterVariable (&joy_advaxisx);
  494.     Cvar_RegisterVariable (&joy_advaxisy);
  495.     Cvar_RegisterVariable (&joy_advaxisz);
  496.     Cvar_RegisterVariable (&joy_advaxisr);
  497.     Cvar_RegisterVariable (&joy_advaxisu);
  498.     Cvar_RegisterVariable (&joy_advaxisv);
  499.     Cvar_RegisterVariable (&joy_forwardthreshold);
  500.     Cvar_RegisterVariable (&joy_sidethreshold);
  501.     Cvar_RegisterVariable (&joy_pitchthreshold);
  502.     Cvar_RegisterVariable (&joy_yawthreshold);
  503.     Cvar_RegisterVariable (&joy_forwardsensitivity);
  504.     Cvar_RegisterVariable (&joy_sidesensitivity);
  505.     Cvar_RegisterVariable (&joy_pitchsensitivity);
  506.     Cvar_RegisterVariable (&joy_yawsensitivity);
  507.     Cvar_RegisterVariable (&joy_wwhack1);
  508.     Cvar_RegisterVariable (&joy_wwhack2);
  509.  
  510.     Cmd_AddCommand ("force_centerview", Force_CenterView_f);
  511.     Cmd_AddCommand ("joyadvancedupdate", Joy_AdvancedUpdate_f);
  512.  
  513.     uiWheelMessage = RegisterWindowMessage ( "MSWHEEL_ROLLMSG" );
  514.  
  515.     IN_StartupMouse ();
  516.     IN_StartupJoystick ();
  517. }
  518.  
  519. /*
  520. ===========
  521. IN_Shutdown
  522. ===========
  523. */
  524. void IN_Shutdown (void)
  525. {
  526.  
  527.     IN_DeactivateMouse ();
  528.     IN_ShowMouse ();
  529.  
  530.     if (g_pMouse)
  531.     {
  532.         IDirectInputDevice_Release(g_pMouse);
  533.         g_pMouse = NULL;
  534.     }
  535.  
  536.     if (g_pdi)
  537.     {
  538.         IDirectInput_Release(g_pdi);
  539.         g_pdi = NULL;
  540.     }
  541. }
  542.  
  543.  
  544. /*
  545. ===========
  546. IN_MouseEvent
  547. ===========
  548. */
  549. void IN_MouseEvent (int mstate)
  550. {
  551.     int    i;
  552.  
  553.     if (mouseactive && !dinput)
  554.     {
  555.     // perform button actions
  556.         for (i=0 ; i<mouse_buttons ; i++)
  557.         {
  558.             if ( (mstate & (1<<i)) &&
  559.                 !(mouse_oldbuttonstate & (1<<i)) )
  560.             {
  561.                 Key_Event (K_MOUSE1 + i, true);
  562.             }
  563.  
  564.             if ( !(mstate & (1<<i)) &&
  565.                 (mouse_oldbuttonstate & (1<<i)) )
  566.             {
  567.                 Key_Event (K_MOUSE1 + i, false);
  568.             }
  569.         }    
  570.             
  571.         mouse_oldbuttonstate = mstate;
  572.     }
  573. }
  574.  
  575.  
  576. /*
  577. ===========
  578. IN_MouseMove
  579. ===========
  580. */
  581. void IN_MouseMove (usercmd_t *cmd)
  582. {
  583.     int                    mx, my;
  584.     HDC                    hdc;
  585.     int                    i;
  586.     DIDEVICEOBJECTDATA    od;
  587.     DWORD                dwElements;
  588.     HRESULT                hr;
  589.  
  590.     if (!mouseactive)
  591.         return;
  592.  
  593.     if (dinput)
  594.     {
  595.         mx = 0;
  596.         my = 0;
  597.  
  598.         for (;;)
  599.         {
  600.             dwElements = 1;
  601.  
  602.             hr = IDirectInputDevice_GetDeviceData(g_pMouse,
  603.                     sizeof(DIDEVICEOBJECTDATA), &od, &dwElements, 0);
  604.  
  605.             if ((hr == DIERR_INPUTLOST) || (hr == DIERR_NOTACQUIRED))
  606.             {
  607.                 dinput_acquired = true;
  608.                 IDirectInputDevice_Acquire(g_pMouse);
  609.                 break;
  610.             }
  611.  
  612.             /* Unable to read data or no data available */
  613.             if (FAILED(hr) || dwElements == 0)
  614.             {
  615.                 break;
  616.             }
  617.  
  618.             /* Look at the element to see what happened */
  619.  
  620.             switch (od.dwOfs)
  621.             {
  622.                 case DIMOFS_X:
  623.                     mx += od.dwData;
  624.                     break;
  625.  
  626.                 case DIMOFS_Y:
  627.                     my += od.dwData;
  628.                     break;
  629.  
  630.                 case DIMOFS_BUTTON0:
  631.                     if (od.dwData & 0x80)
  632.                         mstate_di |= 1;
  633.                     else
  634.                         mstate_di &= ~1;
  635.                     break;
  636.  
  637.                 case DIMOFS_BUTTON1:
  638.                     if (od.dwData & 0x80)
  639.                         mstate_di |= (1<<1);
  640.                     else
  641.                         mstate_di &= ~(1<<1);
  642.                     break;
  643.                     
  644.                 case DIMOFS_BUTTON2:
  645.                     if (od.dwData & 0x80)
  646.                         mstate_di |= (1<<2);
  647.                     else
  648.                         mstate_di &= ~(1<<2);
  649.                     break;
  650.             }
  651.         }
  652.  
  653.     // perform button actions
  654.         for (i=0 ; i<mouse_buttons ; i++)
  655.         {
  656.             if ( (mstate_di & (1<<i)) &&
  657.                 !(mouse_oldbuttonstate & (1<<i)) )
  658.             {
  659.                 Key_Event (K_MOUSE1 + i, true);
  660.             }
  661.  
  662.             if ( !(mstate_di & (1<<i)) &&
  663.                 (mouse_oldbuttonstate & (1<<i)) )
  664.             {
  665.                 Key_Event (K_MOUSE1 + i, false);
  666.             }
  667.         }    
  668.             
  669.         mouse_oldbuttonstate = mstate_di;
  670.     }
  671.     else
  672.     {
  673.         GetCursorPos (¤t_pos);
  674.         mx = current_pos.x - window_center_x + mx_accum;
  675.         my = current_pos.y - window_center_y + my_accum;
  676.         mx_accum = 0;
  677.         my_accum = 0;
  678.     }
  679.  
  680. //if (mx ||  my)
  681. //    Con_DPrintf("mx=%d, my=%d\n", mx, my);
  682.  
  683.     if (m_filter.value)
  684.     {
  685.         mouse_x = (mx + old_mouse_x) * 0.5;
  686.         mouse_y = (my + old_mouse_y) * 0.5;
  687.     }
  688.     else
  689.     {
  690.         mouse_x = mx;
  691.         mouse_y = my;
  692.     }
  693.  
  694.     old_mouse_x = mx;
  695.     old_mouse_y = my;
  696.  
  697.     mouse_x *= sensitivity.value;
  698.     mouse_y *= sensitivity.value;
  699.  
  700. // add mouse X/Y movement to cmd
  701.     if ( (in_strafe.state & 1) || (lookstrafe.value && (in_mlook.state & 1) ))
  702.         cmd->sidemove += m_side.value * mouse_x;
  703.     else
  704.         cl.viewangles[YAW] -= m_yaw.value * mouse_x;
  705.  
  706.     if (in_mlook.state & 1)
  707.         V_StopPitchDrift ();
  708.         
  709.     if ( (in_mlook.state & 1) && !(in_strafe.state & 1))
  710.     {
  711.         cl.viewangles[PITCH] += m_pitch.value * mouse_y;
  712.         if (cl.viewangles[PITCH] > 80)
  713.             cl.viewangles[PITCH] = 80;
  714.         if (cl.viewangles[PITCH] < -70)
  715.             cl.viewangles[PITCH] = -70;
  716.     }
  717.     else
  718.     {
  719.         if ((in_strafe.state & 1) && noclip_anglehack)
  720.             cmd->upmove -= m_forward.value * mouse_y;
  721.         else
  722.             cmd->forwardmove -= m_forward.value * mouse_y;
  723.     }
  724.  
  725. // if the mouse has moved, force it to the center, so there's room to move
  726.     if (mx || my)
  727.     {
  728.         SetCursorPos (window_center_x, window_center_y);
  729.     }
  730. }
  731.  
  732.  
  733. /*
  734. ===========
  735. IN_Move
  736. ===========
  737. */
  738. void IN_Move (usercmd_t *cmd)
  739. {
  740.  
  741.     if (ActiveApp && !Minimized)
  742.     {
  743.         IN_MouseMove (cmd);
  744.         IN_JoyMove (cmd);
  745.     }
  746. }
  747.  
  748.  
  749. /*
  750. ===========
  751. IN_Accumulate
  752. ===========
  753. */
  754. void IN_Accumulate (void)
  755. {
  756.     int        mx, my;
  757.     HDC    hdc;
  758.  
  759.     if (mouseactive)
  760.     {
  761.         if (!dinput)
  762.         {
  763.             GetCursorPos (¤t_pos);
  764.  
  765.             mx_accum += current_pos.x - window_center_x;
  766.             my_accum += current_pos.y - window_center_y;
  767.  
  768.         // force the mouse to the center, so there's room to move
  769.             SetCursorPos (window_center_x, window_center_y);
  770.         }
  771.     }
  772. }
  773.  
  774.  
  775. /*
  776. ===================
  777. IN_ClearStates
  778. ===================
  779. */
  780. void IN_ClearStates (void)
  781. {
  782.  
  783.     if (mouseactive)
  784.     {
  785.         mx_accum = 0;
  786.         my_accum = 0;
  787.         mouse_oldbuttonstate = 0;
  788.     }
  789. }
  790.  
  791.  
  792. /* 
  793. =============== 
  794. IN_StartupJoystick 
  795. =============== 
  796. */  
  797. void IN_StartupJoystick (void) 
  798.     int            i, numdevs;
  799.     JOYCAPS        jc;
  800.     MMRESULT    mmr;
  801.  
  802.      // assume no joystick
  803.     joy_avail = false; 
  804.  
  805.     // abort startup if user requests no joystick
  806.     if ( COM_CheckParm ("-nojoy") ) 
  807.         return; 
  808.  
  809.     // verify joystick driver is present
  810.     if ((numdevs = joyGetNumDevs ()) == 0)
  811.     {
  812.         Con_Printf ("\njoystick not found -- driver not present\n\n");
  813.         return;
  814.     }
  815.  
  816.     // cycle through the joystick ids for the first valid one
  817.     for (joy_id=0 ; joy_id<numdevs ; joy_id++)
  818.     {
  819.         memset (&ji, 0, sizeof(ji));
  820.         ji.dwSize = sizeof(ji);
  821.         ji.dwFlags = JOY_RETURNCENTERED;
  822.  
  823.         if ((mmr = joyGetPosEx (joy_id, &ji)) == JOYERR_NOERROR)
  824.             break;
  825.     } 
  826.  
  827.     // abort startup if we didn't find a valid joystick
  828.     if (mmr != JOYERR_NOERROR)
  829.     {
  830.         Con_Printf ("\njoystick not found -- no valid joysticks (%x)\n\n", mmr);
  831.         return;
  832.     }
  833.  
  834.     // get the capabilities of the selected joystick
  835.     // abort startup if command fails
  836.     memset (&jc, 0, sizeof(jc));
  837.     if ((mmr = joyGetDevCaps (joy_id, &jc, sizeof(jc))) != JOYERR_NOERROR)
  838.     {
  839.         Con_Printf ("\njoystick not found -- invalid joystick capabilities (%x)\n\n", mmr); 
  840.         return;
  841.     }
  842.  
  843.     // save the joystick's number of buttons and POV status
  844.     joy_numbuttons = jc.wNumButtons;
  845.     joy_haspov = jc.wCaps & JOYCAPS_HASPOV;
  846.  
  847.     // old button and POV states default to no buttons pressed
  848.     joy_oldbuttonstate = joy_oldpovstate = 0;
  849.  
  850.     // mark the joystick as available and advanced initialization not completed
  851.     // this is needed as cvars are not available during initialization
  852.  
  853.     joy_avail = true; 
  854.     joy_advancedinit = false;
  855.  
  856.     Con_Printf ("\njoystick detected\n\n"); 
  857. }
  858.  
  859.  
  860. /*
  861. ===========
  862. RawValuePointer
  863. ===========
  864. */
  865. PDWORD RawValuePointer (int axis)
  866. {
  867.     switch (axis)
  868.     {
  869.     case JOY_AXIS_X:
  870.         return &ji.dwXpos;
  871.     case JOY_AXIS_Y:
  872.         return &ji.dwYpos;
  873.     case JOY_AXIS_Z:
  874.         return &ji.dwZpos;
  875.     case JOY_AXIS_R:
  876.         return &ji.dwRpos;
  877.     case JOY_AXIS_U:
  878.         return &ji.dwUpos;
  879.     case JOY_AXIS_V:
  880.         return &ji.dwVpos;
  881.     }
  882. }
  883.  
  884.  
  885. /*
  886. ===========
  887. Joy_AdvancedUpdate_f
  888. ===========
  889. */
  890. void Joy_AdvancedUpdate_f (void)
  891. {
  892.  
  893.     // called once by IN_ReadJoystick and by user whenever an update is needed
  894.     // cvars are now available
  895.     int    i;
  896.     DWORD dwTemp;
  897.  
  898.     // initialize all the maps
  899.     for (i = 0; i < JOY_MAX_AXES; i++)
  900.     {
  901.         dwAxisMap[i] = AxisNada;
  902.         dwControlMap[i] = JOY_ABSOLUTE_AXIS;
  903.         pdwRawValue[i] = RawValuePointer(i);
  904.     }
  905.  
  906.     if( joy_advanced.value == 0.0)
  907.     {
  908.         // default joystick initialization
  909.         // 2 axes only with joystick control
  910.         dwAxisMap[JOY_AXIS_X] = AxisTurn;
  911.         // dwControlMap[JOY_AXIS_X] = JOY_ABSOLUTE_AXIS;
  912.         dwAxisMap[JOY_AXIS_Y] = AxisForward;
  913.         // dwControlMap[JOY_AXIS_Y] = JOY_ABSOLUTE_AXIS;
  914.     }
  915.     else
  916.     {
  917.         if (Q_strcmp (joy_name.string, "joystick") != 0)
  918.         {
  919.             // notify user of advanced controller
  920.             Con_Printf ("\n%s configured\n\n", joy_name.string);
  921.         }
  922.  
  923.         // advanced initialization here
  924.         // data supplied by user via joy_axisn cvars
  925.         dwTemp = (DWORD) joy_advaxisx.value;
  926.         dwAxisMap[JOY_AXIS_X] = dwTemp & 0x0000000f;
  927.         dwControlMap[JOY_AXIS_X] = dwTemp & JOY_RELATIVE_AXIS;
  928.         dwTemp = (DWORD) joy_advaxisy.value;
  929.         dwAxisMap[JOY_AXIS_Y] = dwTemp & 0x0000000f;
  930.         dwControlMap[JOY_AXIS_Y] = dwTemp & JOY_RELATIVE_AXIS;
  931.         dwTemp = (DWORD) joy_advaxisz.value;
  932.         dwAxisMap[JOY_AXIS_Z] = dwTemp & 0x0000000f;
  933.         dwControlMap[JOY_AXIS_Z] = dwTemp & JOY_RELATIVE_AXIS;
  934.         dwTemp = (DWORD) joy_advaxisr.value;
  935.         dwAxisMap[JOY_AXIS_R] = dwTemp & 0x0000000f;
  936.         dwControlMap[JOY_AXIS_R] = dwTemp & JOY_RELATIVE_AXIS;
  937.         dwTemp = (DWORD) joy_advaxisu.value;
  938.         dwAxisMap[JOY_AXIS_U] = dwTemp & 0x0000000f;
  939.         dwControlMap[JOY_AXIS_U] = dwTemp & JOY_RELATIVE_AXIS;
  940.         dwTemp = (DWORD) joy_advaxisv.value;
  941.         dwAxisMap[JOY_AXIS_V] = dwTemp & 0x0000000f;
  942.         dwControlMap[JOY_AXIS_V] = dwTemp & JOY_RELATIVE_AXIS;
  943.     }
  944.  
  945.     // compute the axes to collect from DirectInput
  946.     joy_flags = JOY_RETURNCENTERED | JOY_RETURNBUTTONS | JOY_RETURNPOV;
  947.     for (i = 0; i < JOY_MAX_AXES; i++)
  948.     {
  949.         if (dwAxisMap[i] != AxisNada)
  950.         {
  951.             joy_flags |= dwAxisFlags[i];
  952.         }
  953.     }
  954. }
  955.  
  956.  
  957. /*
  958. ===========
  959. IN_Commands
  960. ===========
  961. */
  962. void IN_Commands (void)
  963. {
  964.     int        i, key_index;
  965.     DWORD    buttonstate, povstate;
  966.  
  967.     if (!joy_avail)
  968.     {
  969.         return;
  970.     }
  971.  
  972.     
  973.     // loop through the joystick buttons
  974.     // key a joystick event or auxillary event for higher number buttons for each state change
  975.     buttonstate = ji.dwButtons;
  976.     for (i=0 ; i < joy_numbuttons ; i++)
  977.     {
  978.         if ( (buttonstate & (1<<i)) && !(joy_oldbuttonstate & (1<<i)) )
  979.         {
  980.             key_index = (i < 4) ? K_JOY1 : K_AUX1;
  981.             Key_Event (key_index + i, true);
  982.         }
  983.  
  984.         if ( !(buttonstate & (1<<i)) && (joy_oldbuttonstate & (1<<i)) )
  985.         {
  986.             key_index = (i < 4) ? K_JOY1 : K_AUX1;
  987.             Key_Event (key_index + i, false);
  988.         }
  989.     }
  990.     joy_oldbuttonstate = buttonstate;
  991.  
  992.     if (joy_haspov)
  993.     {
  994.         // convert POV information into 4 bits of state information
  995.         // this avoids any potential problems related to moving from one
  996.         // direction to another without going through the center position
  997.         povstate = 0;
  998.         if(ji.dwPOV != JOY_POVCENTERED)
  999.         {
  1000.             if (ji.dwPOV == JOY_POVFORWARD)
  1001.                 povstate |= 0x01;
  1002.             if (ji.dwPOV == JOY_POVRIGHT)
  1003.                 povstate |= 0x02;
  1004.             if (ji.dwPOV == JOY_POVBACKWARD)
  1005.                 povstate |= 0x04;
  1006.             if (ji.dwPOV == JOY_POVLEFT)
  1007.                 povstate |= 0x08;
  1008.         }
  1009.         // determine which bits have changed and key an auxillary event for each change
  1010.         for (i=0 ; i < 4 ; i++)
  1011.         {
  1012.             if ( (povstate & (1<<i)) && !(joy_oldpovstate & (1<<i)) )
  1013.             {
  1014.                 Key_Event (K_AUX29 + i, true);
  1015.             }
  1016.  
  1017.             if ( !(povstate & (1<<i)) && (joy_oldpovstate & (1<<i)) )
  1018.             {
  1019.                 Key_Event (K_AUX29 + i, false);
  1020.             }
  1021.         }
  1022.         joy_oldpovstate = povstate;
  1023.     }
  1024. }
  1025.  
  1026.  
  1027. /* 
  1028. =============== 
  1029. IN_ReadJoystick
  1030. =============== 
  1031. */  
  1032. qboolean IN_ReadJoystick (void)
  1033. {
  1034.  
  1035.     memset (&ji, 0, sizeof(ji));
  1036.     ji.dwSize = sizeof(ji);
  1037.     ji.dwFlags = joy_flags;
  1038.  
  1039.     if (joyGetPosEx (joy_id, &ji) == JOYERR_NOERROR)
  1040.     {
  1041.         // this is a hack -- there is a bug in the Logitech WingMan Warrior DirectInput Driver
  1042.         // rather than having 32768 be the zero point, they have the zero point at 32668
  1043.         // go figure -- anyway, now we get the full resolution out of the device
  1044.         if (joy_wwhack1.value != 0.0)
  1045.         {
  1046.             ji.dwUpos += 100;
  1047.         }
  1048.         return true;
  1049.     }
  1050.     else
  1051.     {
  1052.         // read error occurred
  1053.         // turning off the joystick seems too harsh for 1 read error,\
  1054.         // but what should be done?
  1055.         // Con_Printf ("IN_ReadJoystick: no response\n");
  1056.         // joy_avail = false;
  1057.         return false;
  1058.     }
  1059. }
  1060.  
  1061.  
  1062. /*
  1063. ===========
  1064. IN_JoyMove
  1065. ===========
  1066. */
  1067. void IN_JoyMove (usercmd_t *cmd)
  1068. {
  1069.     float    speed, aspeed;
  1070.     float    fAxisValue, fTemp;
  1071.     int        i;
  1072.  
  1073.     // complete initialization if first time in
  1074.     // this is needed as cvars are not available at initialization time
  1075.     if( joy_advancedinit != true )
  1076.     {
  1077.         Joy_AdvancedUpdate_f();
  1078.         joy_advancedinit = true;
  1079.     }
  1080.  
  1081.     // verify joystick is available and that the user wants to use it
  1082.     if (!joy_avail || !in_joystick.value)
  1083.     {
  1084.         return; 
  1085.     }
  1086.  
  1087.     // collect the joystick data, if possible
  1088.     if (IN_ReadJoystick () != true)
  1089.     {
  1090.         return;
  1091.     }
  1092.  
  1093.     if (in_speed.state & 1)
  1094.         speed = cl_movespeedkey.value;
  1095.     else
  1096.         speed = 1;
  1097.     aspeed = speed * host_frametime;
  1098.  
  1099.     // loop through the axes
  1100.     for (i = 0; i < JOY_MAX_AXES; i++)
  1101.     {
  1102.         // get the floating point zero-centered, potentially-inverted data for the current axis
  1103.         fAxisValue = (float) *pdwRawValue[i];
  1104.         // move centerpoint to zero
  1105.         fAxisValue -= 32768.0;
  1106.  
  1107.         if (joy_wwhack2.value != 0.0)
  1108.         {
  1109.             if (dwAxisMap[i] == AxisTurn)
  1110.             {
  1111.                 // this is a special formula for the Logitech WingMan Warrior
  1112.                 // y=ax^b; where a = 300 and b = 1.3
  1113.                 // also x values are in increments of 800 (so this is factored out)
  1114.                 // then bounds check result to level out excessively high spin rates
  1115.                 fTemp = 300.0 * pow(abs(fAxisValue) / 800.0, 1.3);
  1116.                 if (fTemp > 14000.0)
  1117.                     fTemp = 14000.0;
  1118.                 // restore direction information
  1119.                 fAxisValue = (fAxisValue > 0.0) ? fTemp : -fTemp;
  1120.             }
  1121.         }
  1122.  
  1123.         // convert range from -32768..32767 to -1..1 
  1124.         fAxisValue /= 32768.0;
  1125.  
  1126.         switch (dwAxisMap[i])
  1127.         {
  1128.         case AxisForward:
  1129.             if ((joy_advanced.value == 0.0) && (in_mlook.state & 1))
  1130.             {
  1131.                 // user wants forward control to become look control
  1132.                 if (fabs(fAxisValue) > joy_pitchthreshold.value)
  1133.                 {        
  1134.                     // if mouse invert is on, invert the joystick pitch value
  1135.                     // only absolute control support here (joy_advanced is false)
  1136.                     if (m_pitch.value < 0.0)
  1137.                     {
  1138.                         cl.viewangles[PITCH] -= (fAxisValue * joy_pitchsensitivity.value) * aspeed * cl_pitchspeed.value;
  1139.                     }
  1140.                     else
  1141.                     {
  1142.                         cl.viewangles[PITCH] += (fAxisValue * joy_pitchsensitivity.value) * aspeed * cl_pitchspeed.value;
  1143.                     }
  1144.                     V_StopPitchDrift();
  1145.                 }
  1146.                 else
  1147.                 {
  1148.                     // no pitch movement
  1149.                     // disable pitch return-to-center unless requested by user
  1150.                     // *** this code can be removed when the lookspring bug is fixed
  1151.                     // *** the bug always has the lookspring feature on
  1152.                     if(lookspring.value == 0.0)
  1153.                         V_StopPitchDrift();
  1154.                 }
  1155.             }
  1156.             else
  1157.             {
  1158.                 // user wants forward control to be forward control
  1159.                 if (fabs(fAxisValue) > joy_forwardthreshold.value)
  1160.                 {
  1161.                     cmd->forwardmove += (fAxisValue * joy_forwardsensitivity.value) * speed * cl_forwardspeed.value;
  1162.                 }
  1163.             }
  1164.             break;
  1165.  
  1166.         case AxisSide:
  1167.             if (fabs(fAxisValue) > joy_sidethreshold.value)
  1168.             {
  1169.                 cmd->sidemove += (fAxisValue * joy_sidesensitivity.value) * speed * cl_sidespeed.value;
  1170.             }
  1171.             break;
  1172.  
  1173.         case AxisTurn:
  1174.             if ((in_strafe.state & 1) || (lookstrafe.value && (in_mlook.state & 1)))
  1175.             {
  1176.                 // user wants turn control to become side control
  1177.                 if (fabs(fAxisValue) > joy_sidethreshold.value)
  1178.                 {
  1179.                     cmd->sidemove -= (fAxisValue * joy_sidesensitivity.value) * speed * cl_sidespeed.value;
  1180.                 }
  1181.             }
  1182.             else
  1183.             {
  1184.                 // user wants turn control to be turn control
  1185.                 if (fabs(fAxisValue) > joy_yawthreshold.value)
  1186.                 {
  1187.                     if(dwControlMap[i] == JOY_ABSOLUTE_AXIS)
  1188.                     {
  1189.                         cl.viewangles[YAW] += (fAxisValue * joy_yawsensitivity.value) * aspeed * cl_yawspeed.value;
  1190.                     }
  1191.                     else
  1192.                     {
  1193.                         cl.viewangles[YAW] += (fAxisValue * joy_yawsensitivity.value) * speed * 180.0;
  1194.                     }
  1195.  
  1196.                 }
  1197.             }
  1198.             break;
  1199.  
  1200.         case AxisLook:
  1201.             if (in_mlook.state & 1)
  1202.             {
  1203.                 if (fabs(fAxisValue) > joy_pitchthreshold.value)
  1204.                 {
  1205.                     // pitch movement detected and pitch movement desired by user
  1206.                     if(dwControlMap[i] == JOY_ABSOLUTE_AXIS)
  1207.                     {
  1208.                         cl.viewangles[PITCH] += (fAxisValue * joy_pitchsensitivity.value) * aspeed * cl_pitchspeed.value;
  1209.                     }
  1210.                     else
  1211.                     {
  1212.                         cl.viewangles[PITCH] += (fAxisValue * joy_pitchsensitivity.value) * speed * 180.0;
  1213.                     }
  1214.                     V_StopPitchDrift();
  1215.                 }
  1216.                 else
  1217.                 {
  1218.                     // no pitch movement
  1219.                     // disable pitch return-to-center unless requested by user
  1220.                     // *** this code can be removed when the lookspring bug is fixed
  1221.                     // *** the bug always has the lookspring feature on
  1222.                     if(lookspring.value == 0.0)
  1223.                         V_StopPitchDrift();
  1224.                 }
  1225.             }
  1226.             break;
  1227.  
  1228.         default:
  1229.             break;
  1230.         }
  1231.     }
  1232.  
  1233.     // bounds check pitch
  1234.     if (cl.viewangles[PITCH] > 80.0)
  1235.         cl.viewangles[PITCH] = 80.0;
  1236.     if (cl.viewangles[PITCH] < -70.0)
  1237.         cl.viewangles[PITCH] = -70.0;
  1238. }
  1239.